﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Text.RegularExpressions;

namespace SimpleRcon.Tabs
{
    /// <summary>
    /// Interaction logic for RconUserControl.xaml
    /// </summary>
    public partial class RconTab
    {
        private delegate void WriteToBoxDelegate(string message);
        private delegate void SetEnableDelegate(bool isEnable);

        /// <summary>
        /// The Rcon Connection
        /// </summary>
        public SourceRconLib.Rcon rcon = new SourceRconLib.Rcon();
        private string ServerAddress { get; set; }
        private int ServerPort { get; set; }
        private string Password { get; set; }

        public RconTab(Wpf.Controls.TabControl parent, Wpf.Controls.TabItem tab, string serverAddress, string password)
        {
            InitializeComponent();

            // Tab Name
            tab.Header = serverAddress;

            // Events 
            tab.Unloaded += new RoutedEventHandler(tab_Unloaded);

            // Default
            WriteToBox("Connecting......");
            ServerPort = 27015;
            
            // Save Details
            if (serverAddress.Contains(':'))
            {
                ServerAddress = serverAddress.Split(':')[0];
                try
                {
                    ServerPort = int.Parse(serverAddress.Split(':')[1]);
                }
                catch
                {
                    WriteToBox(string.Format("\"{0}\" is not a valid port", serverAddress.Split(':')[1]));
                }
            }
            else
            {
                ServerAddress = serverAddress;
            }
            Password = password;

            // Rcon Events
            rcon.ServerOutput += new SourceRconLib.RconOutput(rcon_ServerOutput);
            rcon.Errors += new SourceRconLib.RconOutput(rcon_Errors);
            
            // Resolve
            Dns.BeginGetHostEntry(ServerAddress, new AsyncCallback(GetHostEntryEnd), password);
        }

        #region Misc

        private void GetHostEntryEnd(IAsyncResult obj)
        {
            IPHostEntry result = Dns.EndGetHostEntry(obj);
            rcon.Connect(new IPEndPoint(result.AddressList[0], ServerPort), Password);
        }

        private void SetEnable(bool isEnable)
        {
            if (Dispatcher.Thread != System.Threading.Thread.CurrentThread)
            {
                Dispatcher.Invoke(new SetEnableDelegate(SetEnable), new object[] { isEnable });
            }
            else
            {
                IsEnabled = isEnable;
                if (isEnable)
                {
                    textbox_Command.Focus();
                }
            }
        }

        void tab_Unloaded(object sender, RoutedEventArgs e)
        {
            rcon.Dispose();
        }

        #endregion

        private void WriteToBox(string text)
        {
            if (richtextbox_Status.Dispatcher.Thread != System.Threading.Thread.CurrentThread)
            {
                richtextbox_Status.Dispatcher.Invoke(new WriteToBoxDelegate(WriteToBox), new object[] { text });
            }
            else
            {
                // If you use appendtext it make paragraphs wich make to much space, if there is a \n in.
                foreach (var item in text.Split('\n'))
                {
                    richtextbox_Status.AppendText(item);
                    richtextbox_Status.Document.ContentEnd.InsertLineBreak();    
                }
                
                richtextbox_Status.ScrollToEnd();
            }
        }

        #region Controls Commands

        private void button_Send_Click(object sender, RoutedEventArgs e)
        {
            SendCommand(textbox_Command.Text);
            textbox_Command.Text = string.Empty;
            textbox_Command.Focus();
        }

        private void textbox_Command_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                e.Handled = true;
                SendCommand(textbox_Command.Text);
                textbox_Command.Text = string.Empty;
            }
        }

        #endregion

        #region Rcon

        private void SendCommand(string command)
        {
            WriteToBox(string.Format("---->> {0}", command));
            rcon.ServerCommand(command);
        }

        /// <summary>
        /// Rcon_s the errors.
        /// Seems like the error is also used for check if you got connected
        /// </summary>
        /// <param name="code">The code.</param>
        /// <param name="data">The data.</param>
        void rcon_Errors(SourceRconLib.MessageCode code, string data)
        {
            switch (code)
            {
                case SourceRconLib.MessageCode.ConnectionFailed:
                    WriteToBox(string.Format("Could not connect to \"{0}:{1}\"", ServerAddress, ServerPort));
                    break;
                case SourceRconLib.MessageCode.ConnectionSuccess:
                    WriteToBox("Connected");
                    SetEnable(true);
                    break;
                case SourceRconLib.MessageCode.JunkPacket:
                    break;
                default:
                    if (data != null)
                    {
                        WriteToBox(string.Format("Error: {0}", data));
                    }
                    break;
            }
        }

        void rcon_ServerOutput(SourceRconLib.MessageCode code, string data)
        {
            switch (code)
            {
                case SourceRconLib.MessageCode.ConsoleOutput:
                    if (!string.IsNullOrEmpty(data))
                    {
                        if (data.Contains("\nL"))
                        {
                            WriteToBox(Regex.Split(data, "\nL")[0]);
                        }
                        else
                        {
                            WriteToBox(data);
                        }
                    }
                    break;
                case SourceRconLib.MessageCode.TooMuchData:
                    WriteToBox("You can not send that much data");
                    break;
                default:
                    // Eha yah sure?
                    break;
            }
        }

        #endregion
    }
}
